/*------------------------------------------------------------------*|
|* FILE:              Pipeline Processor
|* DESCRIPTION:       Processor Simulator
|* DATE:              4.3.2012
|* LANGUAGE PLATFORM: gcc 
|* AUTHOR:            Sajin George
|* EMAIL:             sxg8392@rit.edu
|*------------------------------------------------------------------*/
 
 
#include <stdio.h>
 
 

       
 int Stalls=0,Adds=0,Subs=0,jmps=0,Ceqs=0,Clts=0,Nots=0,Ands=0,Lds=0,Jmps=0,Rets=0,Shs=0,Brs=0,Calls=0,Cpys=0,IOs=0,INADD=0,DADD=0,TOTAL=0;
 char STALL_ALL=0;
 int PIPELINED=0;

/* Each memory word and register can hold a 8-bit value, which
   ranges from 0 to 256.
 
   The program counter can range from 0 to 32, which means that
   the maximum size of a program is  32 instructions.
*/
 
/* Let's use only 8 words of memory instead of 65536 words of memory */
#define MEM_SIZE 32
#define DMEM_SIZE 32
/* We have 8 registers. 
*/
#define REGS     4
 
 
/* Memory is an array of 8-bit HEX words. */
unsigned char mem[ MEM_SIZE ] = {0x33,0x01,0x33,0x01,0x16,0x26,0x42,0x03,0x66,0x30,0x00,0x52,0x12,0xb0,0x00};
/* To run a different program, the program must be hand-asembled and
   entered in place of the one found here. */
   
unsigned char Dmem[ DMEM_SIZE ] = {0};

unsigned char iomem[ 5 ] = {0};

unsigned int stack_top=10;
 
/* Create 4 registers and set them all to 0. */
char reg[ REGS ] = {0};
//store 2PC in mem for pipelining
static char PC=0;
static char PC2=1;
 
//for decoding
char ir;                   /* instruction register */
char op, r1, r2, r3, imm, acc;  /* operand number, register numbers, immediate value */
int  offs;                 /* signed offset value */
char Z,C,N,V;
char r1a,r1b,r2a,r2b;
char temp;
char fetchstall=0,decodestall=0,executestall=0;
char io=0;
 
/* This is used during memory address calculation */
char addr;
 char imm;
/* CPU flags */
int halt = 0;
 
 
/*------------------------------------------------------------------*|
|* Display the entire block of memory in 8 columns.
|*------------------------------------------------------------------*/
void showMem()
{
  int i;
  int w = 0;
  for( i=0; i<MEM_SIZE; i++ )
    {
      printf( "%0.2X:%0.2X ", i, mem[ i ] );
      if( w++ == 7 )
        {
          printf( "\n" );
          w = 0;
        }
    }
  printf( "\n" );
}
 
 
void showDMem()
{
  int i;
  int w = 0;
  for( i=0; i<DMEM_SIZE; i++ )
    {
      printf( "%0.2X:%0.2X ", i, Dmem[ i ] );
      if( w++ == 7 )
        {
          printf( "\n" );
          w = 0;
        }
    }
  printf( "\n" );
} 
 
 
/*------------------------------------------------------------------*|
|* Display all the Data Memory
|*------------------------------------------------------------------*/
void showRegs()
{
   
  int i=0;
  //for( i=0; i<8; i++ )
  //  printf( "%0.1X:%0.2X ", i, reg[ i ] );
  //printf( "\n" );
  for( ; i<REGS; i++ )
    printf( "%0.1X:%0.2X ", i, reg[ i ] );
  printf( "\n" );
  
}
 
 void showPC()
 {
      printf("\nPC1=%d",PC);
            
}
/*------------------------------------------------------------------*|
|* Fetch the next instruction.
|* After a fetch, the PC points to the next instruction in memory.
|*------------------------------------------------------------------*/
int fetch()
{

 // if(fetchstall==0)
 // {   
        
  ir = mem[PC];
  PC++;
  imm=mem [PC]&0xff;
 // if(decodestall==1)
 // fetchstall=1;
 // }
 //  if(decodestall==0)
 //  fetchstall=1;
 return 1;
}
 

 
/*------------------------------------------------------------------*|
|* Decode the last instruction that was fetched.
|* All values are decoded (all 3 registers, immediate, and offset),
|* even if they are not needed.
|*------------------------------------------------------------------*/
int decode()
{
//     if(decodestall==0)
//     {
  op = ir >> 4;          /* get the operation code */
  r1 = (ir >> 2) & 0x3;   /* get the first register */
  r1a= (r1 >> 1) & 0x1;  //bit 11
  r1b= (r1) & 0x1;     //bit 10
  r2 = (ir) & 0x3;   /* get the second register */
  r2a= (r2>>1) & 0x1;  //bit 8
  r2b= (r2) & 0x1;     //bit 9

  printf( "\nir=%0.2X (op=%X r1=%X r2=%X r3=%x imm=%0.2X offs=%d)\n", ir, op, r1, r2, r3, imm, offs+1 );
//    printf( "\nir=%0.4X (op=%X r1=%X r1a=%X r1b=%X r2=%X r2a=%X r2b=%X r3=%x imm=%0.2X offs=%d)\n", ir, op, r1,r1a,r1b, r2,r2a,r2b, r3, imm, offs+1 );
// if(executestall==1){
//  fetchstall=1;    
//  decodestall=1;}
//}
// if(executestall==0)
//  decodestall=0;
return 1;
}
 
 
/*------------------------------------------------------------------*|
|* Execute a decoded instruction.
|*------------------------------------------------------------------*/
void execute()
{
  /* force register 3 always to be 0 */
 
  r3 = 0;
  switch( op )
    {
    case 0:
      /* halt */
      /* halt the CPU */
      halt = 1;
      printf("halt\n");
      return;
 
    case 1:
         Adds++;
      /* add r1, r2*/
      /* add two registers, place in the first */
      acc = reg[ r1 ] + reg[ r2 ];
      printf("add\n");
      break;
 
    case 2:
         Subs++;
      /* sub r1, r2 */
      /* subtract one register from another, place in the first */
      reg[r1] = reg[ r1 ] - reg[ r2 ];
      if(acc<=0)
      Z=0;
            printf("sub\n");
      break;
 
    case 3:
         Lds++;
               printf("LOAD\n");
      /* load a word from memory into register */
      if (r2a==1)// load from mem
      {     //load from instruction mem
            if(r2b==1)
            {
			INADD++;
                      addr = imm;
                      PC++;   //dont read this 
                      reg[ r1 ] = mem[ addr ];
            }
            
      }

      else if (r2a==0) //load from Data mem
      {
           if(r2b==1)
            {
			INADD++;
                      addr = imm;
                      PC++; //dont read this
                      reg[ r1 ] = Dmem[ addr ];
            }
            else if(r2b==0)
            {
			INADD++;
                      addr = imm;
                      PC++; //dont read this
                      acc = reg[(int) r1 ];

                     
                     //acc=1;
                      printf("what ever is in reg %d=%d is copied to acc=%d",r1,reg[r1],acc);
            }
      }
      break;
 
   case 4:// IOs
         printf("IO\n");
      /* sw r1, r2, r3 */
      /* store a word from register into memory */
     // addr = reg[ r2 ] + reg[ r3 ] +imm;
     // mem[ addr ] = reg[ r1 ];
      //break;
     if (r2a==1)
      {
            io=1;
            if(r2b==1)//I
            {
                      addr = imm;
                      PC++;
                      reg[ r1 ] = iomem[ addr ];
            }
            else if(r2b==0)///O
            {
			DADD++;
                      addr = imm ;
                      PC++;
                     iomem[addr] = reg[ r1 ];
            }
      }

 break;

    case 0xA:
               printf("AND\n");
          Ands++;
      /* lli r1, immediate(8-bit) */
      /* load low half of register with an immediate value */
      //reg[ r1 ] &= 0xFF00;
      //reg[ r1 ] |= imm;
            reg[ r1 ] = reg[ r1 ] & reg[ r2 ];
      break;
 
    case 6:
         Ceqs++;
      /* lhi r1, immediage(8-bit) */
      /* load high half of register with an immediate value */
//      reg[ r1 ] &= 0xFF00;
  //    reg[ r1 ] |= imm << 8;
          if(reg[ r1 ] == reg[ r2 ])
          {
                  Z=1;
          }
    
    
      break;
 
    case 0xB:
               printf("CLTs\n");
         Clts++;
      /* mv r1, r2 */
      /* copy contents of r2 into r1 */
//      reg[ r1 ] = reg[ r2 ];
        if(reg[r1]>reg[r2])
        {
                     N=1;
        }
      break;
 
    case 8:
               printf("NOT\n");
         Nots++;
      /* jmp address(16-bit) */
      /* jump to a 16-bit address */
      //addr = mem[ reg[ PC ] ];
      //reg[ PC ] = addr;
      reg[r1]=~(reg[r1]);
      break;
 
    case 9:
               printf("SH\n");
         Shs++;
      /* br r1, offset(8-bit signed) */
      /* branch to register + offset */
      //reg[ PC ] += reg[ r1 ] + offs;
      if(r2a==1)
      {
                reg[r1]=reg[r1]>>1;
      }
      else if(r2a==0)
      {
                           reg[r1]=reg[r1]<<1;
      }
      break;
 
    case 5:
               printf("JMP\n");
      /* br r1, offset(8-bit signed) */
      /* branch by offset if r1 == 0 */
      //if( reg[ r1 ] == 0 )
       // reg[ PC ] += offs;
Jmps++;
DADD++;

    //   executestall=1;
       Stalls++;
       STALL_ALL=1;
      Dmem [stack_top]=PC-2;
      stack_top--;
       
               if(r1a=1)
               {
                  if(C=1)
                         {
                            PC = imm;
                         }
   
                }
                else if(r1b=1)
                {
                     if(N=1)
                     {
                            PC = imm;
                     }
                }
              
                else if(r2a=1)
                {
                     if(Z=1)
                     {
                            PC = imm;
                     }
                }
                else if(r2b=1)
                {
                     if(V=1)
                     {
                           PC = imm;
                     }
                }
                else if((r1a=1)&(r1b=1))
                {
                      if((C=1)&(N=1))
                      {
                      PC = imm;
                      }
                }
                else if((r1a=1)&(r2a=1))
                {
                       if((C=1)&(Z=1))
                       {
                       PC = imm;
                       }
                }
                else
                {
                       PC = imm;
                }
      
      break;
 
    case 7:
      printf("RET\n");
         //return
         Rets++;
stack_top++;
      PC=Dmem[stack_top];
            
      PC++;
      break;
 
    case 0xC:
         Cpys++;
		 DADD++;
               printf("cpy-swap\n");
      /* unused */
      temp=reg[r1];
      reg[r1]=reg[r2];
      reg[r2]=temp;
      
      break;
 
    case 0xD:
         
      /* unused */
      Cpys++;
	  DADD++;
               printf("cpy-swap\n");
      /* unused */
      reg[r1]=imm;
      break;
 
    case 0xE:
      /* out r1 */
      /* display the value of a register */
      printf( "program output: %u\n", reg[ r1 ] );
      break;
 
    case 0xF:
      /* unused */
      break;
    }
// return 1;
//}
}
 
 
 int write()
 {
     STALL_ALL=0;    
     Dmem[addr]=acc;
     return 1;
 }
 
 void show()
 {
  printf( "\nMemory:\n" );
  showMem();
  printf( "\nData Memory:\n" );
  showDMem();
  printf( "Registers:\n" );
  showRegs();
  showPC();
  }
/*------------------------------------------------------------------*|
|* Run the CPU until it halts.
|*------------------------------------------------------------------*/
void run()
{
unsigned char fetchStatus=0,decodeStatus=0,executeStatus=0,writeStatus=0;

  while( !halt )
  {

show();
getchar();


if(PIPELINED==0)
{
         fetch();
         show();
         printf("*************************fetching************************\n");
         getchar();
         show();
         decode();
         printf("*************************Decode************************\n");
         show();
         getchar();
         show();
         execute();
         show();
         getchar();
         show();
         getchar();
         write();
         getchar();
         printf("*************************fetching************************\n");
         fetch();
         show();
         getchar();
         show();
         decode();
         show();
         getchar();
         show();
                  printf("*************************Excute************************\n");
         execute();
         show();
         getchar();
         show();
         getchar();
                  printf("*************************write************************\n");
         write();
         getchar();

                }
                else
                {

fetch(PC);

decode(PC);
fetch(PC2);

execute(PC);


if(STALL_ALL==1)
{
write(PC);
decode(PC2);
execute(PC2);
write(PC2);
}

else
{

decode(PC2);

write(PC);

execute(PC2);

write(PC2);
show();
getchar();
}
}       
/*
//stage 1
<<<<<<< .mine
show();
=======
printf("fetch");
show();
>>>>>>> .r4
fetchStatus=fetch();
getchar();

if(fetchStatus)
{

               //stage 2
printf("decode");
show();
decodeStatus=decode();
printf("fetch");
show();
fetchStatus=fetch();
getchar();
}

if(decodeStatus==1 && fetchStatus==1)
{
printf("execute");
show();
executeStatus=execute();
if(executeStatus==1)
{
printf("decode");
show();
decodeStatus=decode();
printf("fetch");
show();
fetchStatus=fetch();
getchar();
} 
}
if(executeStatus==1)
show();
write();
<<<<<<< .mine
show();
=======
getchar();
*/




}



      getchar(); /* pause until user hits ENTER */
      
   
//  showRegs();
}
 
 
/*------------------------------------------------------------------*|
|* Main program.  This displays some information, then calls run().
|*------------------------------------------------------------------*/
int main()
{
  
  run();
  
//  printf( "\nMemory:\n" );
//  showMem();
//  printf("\n Metrics\n");
TOTAL=Adds+Subs+Jmps+Ceqs+Clts+Nots+Ands+Lds+Rets+Shs+Brs+Calls+Cpys+1;
printf("\n Stalls=%d,\n Adds=%d,\n Subs=%d,\n jmps=%d,\n Ceqs=%d,\n Clts=%d,\n Nots=%d,\n Ands=%d,\n Lds=%d,\n Jmps=%d,\n Rets=%d,\n Shs=%d,\n Brs=%d,\n Calls=%d,\n Cpys=%d \nDirect Addressing was used %d times \nIndirect Addressing was used %d time \n Total No. Of instructions %d",Stalls,Adds,Subs,Jmps,Ceqs,Clts,Nots,Ands,Lds,Jmps,Rets,Shs,Brs,Calls,Cpys,DADD,INADD,TOTAL); 
  getchar();
}
 
 
/*------------------------------------------------------------------*|
|* eof
|*------------------------------------------------------------------*/
